iT邦幫忙

2026 iThome 鐵人賽

DAY 15
0
Claude AI

AI 負責答,我負責讓答案可信——公部門工程師的 30 天 Claude 協作紀律系列 第 15 篇

Day 15:連錯誤訊息都沒留下,怎麼查出是誰把封包擋掉了

  • 分享至 

  • xImage
  •  

Day 15:連錯誤訊息都沒留下,怎麼查出是誰把封包擋掉了

今天的案例,是一種比崩潰更難處理的狀況——系統沒有當機、沒有報錯,只是使用者一直抱怨畫面「一直斷線、一直閃爍」,而伺服器端連一行像樣的錯誤訊息都沒留下。 這種「沒有異常」的異常,最考驗的是怎麼從一堆正常的日誌裡,找出那個消失的封包到底去了哪裡。

症狀:瀏覽器丟出一句籠統的錯誤

系統是用 Blazor Server 架構做的內部網頁,畫面會不斷閃爍、重新整理,瀏覽器主控台跳出一句:「Failed to start the transport 'WebSockets': There was an error with the transport」。

Blazor Server 底層走的是 SignalR,預設會優先嘗試用 WebSocket 建立長連線。AI 一開始列出的可能原因很制式:防火牆擋協定、代理伺服器沒轉發 Upgrade 標頭、反向代理設定缺漏——都是合理的猜測方向,但都還只是列表,沒有指向任何具體的環節。

第一個轉折:AI 誤讀了一張「基準線」截圖,被人糾正

我補充説明:主機上有 nginx 做反向代理,但「nginx 到後端服務」這段本機測試是正常的,只有「從 Internet 經過 nginx 進來」才會出問題。AI 順著這個資訊,判斷問題出在 nginx 的 WebSocket 標頭轉發設定,並給了該補的設定。我照著加上 proxy_http_version 1.1 跟 Upgrade/Connection 標頭之後,問題依然存在。

往下查瀏覽器的開發者工具,AI 抓到一個關鍵線索:「回應標頭」那一欄完全是空的,旁邊寫著「目前顯示佈建標頭(Provisional headers are shown)」——這代表瀏覽器連對方的任何回應都沒收到,包括 101、400、502 這些狀態碼,請求送出去之後直接石沉大海。AI 判斷方向是外部連線在中途被攔截。

但這個判斷建立在一個沒有被檢查過的前提上——AI 以為「本機測試正常」那個對照組是完全繞過 nginx 的。我糾正了這一點:

「剛剛給你的第 2 張截圖 URL 上的 https://127.0.0.1/xxxxx,就是通過 nginx 喔(這個畫面是在 nginx 本機上截圖的)。」

這句話直接把 AI 前面的判斷推翻。它立刻承認:「這個資訊很關鍵,它改變了整個排查方向。」——因為如果「正常」跟「異常」這兩條路徑走的其實是同一台 nginx、同一份設定,那問題幾乎可以確定不在 nginx 的 proxy 設定本身,而是「用內網位址/127.0.0.1 存取」跟「用對外網域從 Internet 存取」之間,中途多經過了什麼東西——重新懷疑到有另一層設備(VPN 閘道之類)介入外部連線。

這個轉折很值得記一筆:AI 不是憑空推理錯的,是我提供的測試結果本身帶著一個沒有講清楚的前提(這張截圖到底有沒有經過 nginx),AI 順著表面資訊往下推,一路推到看起來很合理的結論,直到我補上這個關鍵背景,方向才整個扳正。

用 access log 當客觀裁判,逐層鎖定範圍

我提議一個很直接的排查法:查 nginx 的 access log,看同一時間點有沒有外部連線進來的紀錄。AI 把這個方法的判讀邏輯講得很清楚:

  • log 完全沒這筆紀錄 → 請求根本沒到這台 nginx,問題在更前面
  • log 有紀錄但狀態碼異常 → 問題在 nginx 跟後端之間
  • log 有紀錄且是 101 或 200 → nginx 這層是乾淨的,問題在後面

這是一個不需要更多工具、純粹靠既有證據就能把範圍切成三段的方法,而且每一段的判讀標準都先講清楚,不是拿到 log 之後再各自解讀。

真相:封包連 nginx 都沒有到,但偽裝成了「正常運作」

拿到 log 之後,AI 讀出了三個關鍵發現:

第一,整份 log 完全沒有出現過 101 狀態碼——這是 WebSocket 升級成功才會有的回應。但 log 裡卻塞滿了一種特定模式:一堆帶時間戳記參數、GET/POST 交替出現、回應內容只有幾個位元組的請求。AI 判斷這正是 SignalR 在 WebSocket 建立失敗後,自動退回使用「Long Polling」傳輸方式的典型特徵——不是真正的長連線,是短輪詢偽裝成看似正常的一堆 200 回應。這解釋了「系統看起來還能動,但一直閃爍」的體感:長連線建不起來,靠短輪詢硬撐。

第二,也是最關鍵的一點:WebSocket 升級請求本身,完全沒有出現在這份 log 裡。 如果 nginx 有收到升級請求,不管成功還是失敗,正常都會留下一筆紀錄。log 裡完全找不到,代表這個請求在到達 nginx 之前,就已經在更前面的網路路徑上被攔截或丟棄了——這也回頭解釋了瀏覽器那句「Provisional headers are shown」:不是 nginx 拒絕了它,是它根本沒能抵達 nginx。

第三,來源 IP 是使用者的真實公網 IP,不是內部轉址設備常見的內網位址,這推翻了 AI 前一輪懷疑的「經由某種反代模式轉送」的猜測,改而指向:中間有一台設備只針對 WebSocket 升級這種特徵的封包做攔截,一般 HTTP 請求則正常放行——這種行為在會做深度封包檢測的資安閘道設備上並不少見。

這一天的結論:沒有真的抓到兇手,但把嫌疑範圍鎖到精準的一句話

這個案子最後沒有一個「找到了、修好了」的漂亮結尾——它停在一句可以直接拿去問資安設備廠商的具體問題:「為什麼一般 HTTP 都沒事,但 WebSocket 升級的封包會被擋?」 治標的做法是先讓 SignalR 強制只用 Long Polling,犧牲效能換穩定;治本則要靠對方檢查閘道設備的規則設定,已經超出這一端能單獨解決的範圍。

回頭看整個過程,AI 的價值在於把日誌裡一堆看似正常的雜訊,讀出背後真正的傳輸機制(辨認出 Long Polling 偽裝、判斷升級請求根本沒送達),這需要對 SignalR、HTTP 升級機制的底層知識,人不一定隨手就有。但真正決定排查方向有沒有走偏的,是我糾正的那個關鍵前提——AI 沒辦法自己發現一張截圖背後「到底測的是什麼」,除非我告訴它。 一個沒講清楚的測試條件,會讓 AI 順著表面資訊推導出一個看起來完整、卻建立在錯誤基礎上的結論。這又是一次「脈絡要餵齊全,AI 才給得準」的示範,只是這次的脈絡不是背景知識,是測試本身的真正涵蓋範圍。


明天我想先停下來,回頭盤點這十幾天實戰篇裡,反覆出現的幾個共通模式——AI 什麼時候可靠、什麼時候會系統性地出錯,人在其中真正無法被取代的,到底是哪幾件事。


上一篇
Day 14:沒有 bug、沒有崩潰,AI 在這次協作裡到底幫了什麼
系列文
AI 負責答,我負責讓答案可信——公部門工程師的 30 天 Claude 協作紀律 共 15 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言